#include "widget.h"
#include "libgui.h"
#include "lcd_rgb.h"

struct window_t *cw;//current_window
struct window_t *get_current_window(void)
{
    return cw;
}
void set_current_window(struct window_t *w)
{
    if(w == NULL) return ;
    cw = w;
}


void mouse_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{
	return;
	
	//控件很难被点击到
    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,ev);

}
void mouse_init(struct window_t *window, struct genery_param_t *p)
{
    p->cb_widget = mouse_event_response;
    
    int16_t x2 = p->x + (p->h);
    int16_t y2 = p->y + (p->w/2);
    int16_t x3 = p->x+(p->w)/2;
    int16_t y3 = p->y+(p->h);
    
    
    LCD_DrawFillTriangle(window,p->x,p->y,x2,y2,x3,y3,p->color);
    LCD_DrawFillTriangle(window,p->x+p->w+1,p->y+p->h+1,x2,y2+1,x3,y3,p->bc);

}

void timer_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{

}
void timer_init(struct window_t *window, struct genery_param_t *p)
{
    p->cb_widget = timer_event_response;

}


void meter_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{
    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,0);
}


void get_point_on_circle(int16_t angle,int16_t r,int16_t *a,int16_t *b)
{
    //获取圆周上的点
    *a = r * cos(angle * 3.14 /180);
    *b = r * sin(angle * 3.14 /180);
}
void meter_init(struct window_t *window, struct genery_param_t *p)
{
    p->cb_widget = meter_event_response;
    uint16_t x = (p->x + p->w)/2;
    uint16_t y = (p->y + p->w)/2;
    uint16_t r = p->w/2;
    int16_t angle = (p->value *360 /(p->max - p->min)) % 360;
    LCD_DrawFillCircle(window,x,y,r,p->bc);//底板圆盘填充
    LCD_DrawCircle(window,x,y,r+1,p->color);//圆盘边
    
    
    //刻度
    int16_t a1,b1;
    int16_t a2,b2;
    int16_t a3,b3;
    int16_t a4,b4;
    uint16_t color = 0;
    for(int i=0;i<360;i+=15){
        get_point_on_circle(i-90,100,&a1,&b1);
        get_point_on_circle(i-90,90,&a2,&b2);
        color = (!(i%90))?p->fc:p->color;
        LCD_DrawLine(window,x+a1,y+b1,x+a2,y+b2,color);
    }

 
    //指针
    get_point_on_circle(angle,10,&a1,&b1);
    get_point_on_circle(angle-90,100,&a3,&b3);
    if(angle>180){
        get_point_on_circle(angle-180,10,&a2,&b2);
        get_point_on_circle(angle-90-180,20,&a4,&b4);
    }else{
        get_point_on_circle(angle+180,10,&a2,&b2);
        get_point_on_circle(angle-90-180,20,&a4,&b4);
    }
    LCD_DrawFillTriangle(window,x+a1,y+b1,x+a2,y+b2,x+a3,y+b3,p->color);
    LCD_DrawFillTriangle(window,x+a1,y+b1,x+a2,y+b2,x+a4,y+b4,p->color);
    
    //指针原点圆环
    LCD_DrawCircle(window,x,y,7,p->fc);
    LCD_DrawCircle(window,x,y,6,p->fc);
    LCD_DrawCircle(window,x,y,5,p->fc);
    
  
}   

void icon_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{
    if(ev == TS_EV_SHORT_PRESS){
        set_current_window(param->page);
    }
    
    if(ev == TS_EV_RELEASE){
        //set_current_window(param->page);
    }
    
    if(ev == TS_EV_LONG_PRESS){
        ev |= GUI_EV_LONG_PRESS;
    }    

    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,ev);

}

void icon_init(struct window_t *window, struct genery_param_t *p)
{
    p->cb_widget = icon_event_response;
    int fsize = p->frame_size;
    LCD_DrawFillRectangle(window,p->x ,p->y ,p->x + p->w ,p->y + p->h,p->bc);
    LCD_DrawCircle(window,p->x+p->w/2,p->y+p->h/2,50,p->frame_size);
    //LCD_DrawString(window,p->x,p->y,p->text,p->fc,p->fc,0,font.f0816);
    LCD_DrawString(window,p->x+p->w/2 -font.f4896->width/2,p->y,p->text,p->fc,p->bc,0,font.f4896);
    
}
void button_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y) 
{    
    if(ev == TS_EV_RELEASE){
        set_current_window(param->page);
    }

    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,ev);

}
void button_init(struct window_t *window, struct genery_param_t *p)
{
    uint16_t wx = 0;    
    int fsize = p->frame_size;
    int text_offset = p->frame_size *2;
    p->cb_widget = button_event_response;
    
    
#if 0    
    
    int16_t x = p->x;
    int16_t y = p->y;
    int16_t w = p->w;
    int16_t h = p->h;
    int16_t r = (float)w * 0.1;
    //LCD_DrawFillRectangle(window,x,y,x+w,y+h,LCD_WHITE);
    
    //四个圆角
    LCD_DrawFillCircle(window,x+r,y+r,r,p->bc);
    LCD_DrawFillCircle(window,x+w-r,y+r,r,p->bc);
    LCD_DrawFillCircle(window,x+r,y+h-r,r,p->bc);
    LCD_DrawFillCircle(window,x+w-r,y+h-r,r,p->bc);
    
    //中间填充
    LCD_DrawFillRectangle(window,x+r,y,x+w-r,y+h,p->bc);
    LCD_DrawFillRectangle(window,x,y+r,x+r,y+h-r,p->bc);
    LCD_DrawFillRectangle(window,x+w-r,y+r,x+w,y+h-r,p->bc);
    
    //中间线条
    int16_t r2 = r/2;
    LCD_DrawArc1(window,x+r,y+r,90,180,r/2,p->frame_color);
    LCD_DrawArc1(window,x+w-r,y+r,0,90,r/2,p->frame_color);
    LCD_DrawArc1(window,x+r,y+h-r,180,270,r/2,p->frame_color);
    LCD_DrawArc1(window,x+w-r,y+h-r,270,360,r/2,p->frame_color);
    LCD_DrawLine(window,x+r,y+r2,x+w-r,y+r2,p->frame_color);
    LCD_DrawLine(window,x+r2,y+r,x+r2,y+h-r,p->frame_color);
    LCD_DrawLine(window,x+r,y+h-r2,x+w-r,y+h-r2,p->frame_color);
    LCD_DrawLine(window,x+w-r2,y+r,x+w-r2,y+h-r,p->frame_color);

    //文字
    //LCD_DrawString(window,p->x +fsize +text_offset,p->y +fsize +text_offset,p->text,p->fc,p->bc,0,font.f0816);
    
    //文字居中
    int string_len = strlen(p->text);
    LCD_DrawString(window, \
    (p->x + p->w/2) - font.f0816->width * (string_len/2), \
    (p->y + p->h/2)- (font.f0816->hight/2), \
    p->text,p->fc,p->bc,0,font.f0816);
    
#else

	//中间背景 + 四周边框
    LCD_DrawFillRectangle(window,p->x +fsize,p->y +fsize,p->x + p->w -fsize,p->y + p->h-fsize,p->bc);
    LCD_DrawFillRectangle(window,p->x,p->y,p->x + p->w,p->y + fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y +p->h-fsize,p->x + p->w,p->y +p->h,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y +fsize,p->x + fsize,p->y +p->h -fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x +p->w -fsize,p->y +fsize,p->x +p->w,p->y +p->h-fsize,p->frame_color);

	//文字居中
    int string_len = strlen(p->text);
    LCD_DrawString(window, \
    (p->x + p->w/2) - font.f0816->width * (string_len/2), \
    (p->y + p->h/2)- (font.f0816->hight/2), \
    p->text,p->fc,p->bc,0,font.f0816);
#endif
	return ;
}




void sw_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{
    if(ev != TS_EV_RELEASE) return;

    if(param->w == param->h){
        param->value = !param->value;
    }
    
    if(param->w > param->h){
        int left_right = x > param->x + (param->w/2);//true = right
        param->value = (left_right) ? 1 : 0 ;
    }
    
    if(param->w < param->h){
        int up_down = y > param->y + (param->h/2);
        param->value = (up_down) ? 1 : 0 ;
    }
    

    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,GUI_EV_VALUE_CHANGE);

}
void sw_init(struct window_t *window, struct genery_param_t *p)
{
    int fsize = p->frame_size;
    int text_offset = p->frame_size;
    p->cb_widget = sw_event_response;

    
#if 1 
    
    //横向控件 则使用高度(短边)做参考尺寸, 反之使用宽度做参考, 长宽一致则使用高度
    int16_t w = p->w,h = p->h;
    int16_t x = p->x,y = p->y;
    int16_t ref = (w<h)?w:h;
    
    int16_t r = ref/2;
    int16_t offset = (float)ref * 0.08;

	//外框
    LCD_DrawFillCircle(window,x+r,y+r,r,p->frame_color);
    LCD_DrawFillCircle(window,x+w-r,y+h-r,r,p->frame_color);
    if(ref == p->w){
        LCD_DrawFillRectangle(window,x,y+r,x + w,y +h-r,p->frame_color);
    }else{
        LCD_DrawFillRectangle(window,x+r,y,x + w-r,y + h,p->frame_color);
    }
    
    r -= offset;
    x += offset;
    y += offset;
    w -= offset *2;
    h -= offset *2;
    
	//背景框
    LCD_DrawFillCircle(window,x+r,y+r,r,p->bc);
    LCD_DrawFillCircle(window,x+w-r,y+h-r,r,p->bc);
    if(ref == p->w){
        LCD_DrawFillRectangle(window,x,y+r,x + w,y +h-r,p->bc);
    }else{
        LCD_DrawFillRectangle(window,x+r,y,x + w-r,y + h,p->bc);
    }
    
    //圆点
    r -= offset;
    x += offset;
    y += offset;
    w -= offset *2;
    h -= offset *2;
    if(p->value){
        LCD_DrawFillCircle(window,x+w-r,y+h-r,r,p->color_on);
    }else{
        LCD_DrawFillCircle(window,x+r,y+r,r,p->color_off);
    }

    
#else
    
    
    
    
    LCD_DrawFillRectangle(window,p->x +fsize,p->y +fsize,p->x + p->w -fsize,p->y + p->h-fsize,p->bc);
    LCD_DrawFillRectangle(window,p->x,p->y,p->x + p->w,p->y + fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y +p->h-fsize,p->x + p->w,p->y +p->h,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y +fsize,p->x + fsize,p->y +p->h -fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x +p->w -fsize,p->y +fsize,p->x +p->w,p->y +p->h-fsize,p->frame_color);
    
    int mid_x = (p->w)/2;
    int mid_y = (p->w)/2;
    if(p->value){
        LCD_DrawFillRectangle(window,p->x+p->w -mid_x +fsize/2,p->y +fsize*2,p->x+p->w -fsize*2,p->y +p->h -fsize*2,p->color);
    }else{
        LCD_DrawFillRectangle(window,p->x +fsize*2,p->y +fsize*2,p->x+p->w -mid_x -fsize/2,p->y +p->h -fsize*2,p->color);
    }
#endif
    return ;
}


void bar_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{
	if(param->w > param->h){
		param->value = (x - param->x) / (param->w/param->max);//scale
		if(param->value <param->min)param->value = param->min;
		if(param->value >param->max)param->value = param->max;
		
	}else{
		param->value = (y - param->y) / (param->h/param->max);
		if(param->value <param->min)param->value = param->min;
		if(param->value >param->max)param->value = param->max;
		param->value = param->max - param->value;
	}
    
	
	
    //实际输入和参数之间应做缩放，不然两头不容易触摸到，或者放大触控面积
    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,GUI_EV_VALUE_CHANGE);

}
void bar_init(struct window_t *window, struct genery_param_t *p)
{
    p->cb_widget = bar_event_response;

	//背景和边框
    int fsize = p->frame_size;
    LCD_DrawFillRectangle(window,p->x +fsize,p->y +fsize,p->x + p->w -fsize,p->y + p->h-fsize,p->bc);
    LCD_DrawFillRectangle(window,p->x,p->y,p->x + p->w,p->y + fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y +p->h-fsize,p->x + p->w,p->y +p->h,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y +fsize,p->x + fsize,p->y +p->h -fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x +p->w -fsize,p->y +fsize,p->x +p->w,p->y +p->h-fsize,p->frame_color);
    
	
	//判断横向还是竖向
	if(p->w > p->h){
		int value = p->value * ((float)(p->w- fsize *2)/p->max);
		if(value > 0){
			int16_t ax = p->x +fsize;
			int16_t ay = p->y +fsize;
			int16_t bx = p->x + (fsize) +value;
			int16_t by = p->y + p->h -fsize;
			LCD_DrawFillRectangle(window,ax,ay,bx,by,p->color);
		}
	
	}else{
		int value = p->value * ((float)(p->h- fsize *2)/p->max);
		if(value > 0){
			int16_t ax = p->x + fsize;
			int16_t ay = p->y + p->h - fsize;
			int16_t bx = p->x + p->w - fsize;
			int16_t by = p->y + p->h - fsize - (value);
			LCD_DrawFillRectangle(window,ax,ay,bx,by,p->color);
		}
	}

    
    return ;
}

void txtbox_event_response(struct genery_param_t *param,uint8_t ev,int16_t x,int16_t y)
{

    int up_or_down = y > param->y + (param->h/2);//true = down
    param->scroll = (up_or_down) ? param->scroll +1 : param->scroll -1;

	
    if(param->cb_event == NULL)return;
    void (*cb)(struct genery_param_t *,enum TS_EVENT) = param->cb_event;
    cb(param,ev);

}

void textbox_init(struct window_t *window, struct genery_param_t *p)
{
    uint16_t x1 = p->x;
    uint16_t y1 = p->y;
    uint16_t x2 = x1 + p->w;
    uint16_t y2 = y1 + p->h;
    uint16_t x3 = x1 + p->frame_size;
    uint16_t y3 = y1 + p->frame_size;
    p->cb_widget = txtbox_event_response;
    
	//边框
    LCD_DrawFillRectangle(window,x1,y1,x2,y2,p->bc);
    LCD_DrawRectangle(window,x1,y1,x2,y2,p->frame_color);
	LCD_DrawMesh(window,x1,y1,x2,y2,p->frame_color);
	
	//计算并显示内存占用率
	char string_buffer[8] = {0};		
	int text_len = strlen(p->text);
	int16_t string_len = snprintf(string_buffer,8,"%d%%",text_len*100/p->max);
	LCD_DrawString(window,p->x+p->w-p->frame_size-(font.f0816->width * (string_len +0)),p->y+0, \
	string_buffer,BLACK,p->bc,0,font.f0816);
		
		
    uint16_t x=0,y=0;
    char *str = p->text;
    uint16_t s1=0,w=8,h=4;
    
    w = (p->w - p->frame_size *2) / font.f0816->width;//当前窗口一行容纳多少个字
    h = (p->h - p->frame_size *2) / font.f0816->hight;//当前窗口容纳多少行
    
    str = p->text;
    uint16_t a = 0,line = 0;//line=文本总行数
		
    //预计算字符行数
    while(*str){
        if(*str == '\n'){
            a=0;
            line ++;
            str++;
        }
        if(a>=w){
            a=0;
            line ++;
        }
        a++;
        str++;
    }
    
    line += 2;
    int scroll = (line >h)?line-h:0;

	//计算滑动进度条时显示的位置
	scroll += p->scroll;
	if(scroll < 0){
		scroll = 0;
		if(p->scroll<(line-h))p->scroll = -(line-h);
	}
	
	if(scroll > (line-15)){
		scroll = line-15;
		if(p->scroll > (0)) p->scroll = 0;
	}

		
	//再次遍历字符串并根据窗口大小显示
    str = p->text;
    while(*str){
        if(*str == '\n'){
            x=0;
            y ++;
            str++;
        }
        if(x>=w){
            x=0;
            y ++;
        }
        if(y >= scroll && y < (scroll + h)){
            LCD_DrawChar(window,x3 +font.f0816->width *x +(0), \
            y3 + font.f0816->hight *(y-scroll) +(0),*str,p->fc,p->bc,0,font.f0816);
        }
        x++;
        str++;
    }
    
	//显示进度条
    if(h<=line){
        uint16_t value = p->h / (y +0);
        int scroll_unit = (float)p->h / (line -0);//-1
        int scroll_length = scroll_unit * h;
        int scroll_start = p->y + (scroll *scroll_unit);
        LCD_DrawLine(window,x2-p->frame_size/2,scroll_start, \
        x2-p->frame_size/2,scroll_start + scroll_length,p->fc);
    }


}


void battery_init(struct window_t *window, struct genery_param_t *p)
{

#if 0   
    
    int fsize = p->frame_size; 
    LCD_DrawFillRectangle(window,p->x,p->y,p->x + p->w,p->y + fsize,p->bc);
    LCD_DrawFillRectangle(window,p->x,p->y +p->h-fsize-1,p->x + p->w,p->y +p->h,p->bc);    
    LCD_DrawFillRectangle(window,p->x,p->y +fsize +(1),p->x + fsize +(1),p->y +p->h -fsize -(0),p->bc);    
    LCD_DrawFillRectangle(window,p->x +p->w -fsize -(0),p->y +fsize +(1),p->x +p->w -(0),p->y +p->h-fsize -(0),p->bc +0);
    
    
    int value = p->value * ((float)(p->w- fsize *(1.5 *2))/100);
    LCD_DrawFillRectangle(window,p->x +fsize +(2),p->y +fsize +(1),p->x + p->w -fsize -(1),p->y + p->h -fsize +(0),WHITE);//100% WHITE
    //if(value)
    LCD_DrawFillRectangle(window,p->x +fsize*1.5,p->y +fsize*1.5,p->x + (fsize * 1.5) +value,p->y + p->h -(fsize * 1.5) ,p->frame_color);
    //LCD_DrawFillRectangle(window,p->x +(p->w *1) +fsize,p->y +fsize,p->x + p->w +fsize*2,p->y + p->h - fsize,p->bc);
#else    
    int fsize = p->frame_size;
    LCD_DrawFillRectangle(window,p->x +fsize,p->y +fsize,p->x + p->w -fsize,p->y + p->h-fsize,p->frame_color);
    LCD_DrawFillRectangle(window,p->x,p->y,p->x + p->w,p->y + fsize,p->bc);
    LCD_DrawFillRectangle(window,p->x,p->y +p->h-fsize,p->x + p->w,p->y +p->h,p->bc);
    LCD_DrawFillRectangle(window,p->x,p->y +fsize,p->x + fsize,p->y +p->h -fsize,p->bc);
    LCD_DrawFillRectangle(window,p->x +p->w -fsize,p->y +fsize,p->x +p->w,p->y +p->h-fsize,p->bc);
    
    int value = p->value * ((float)(p->w- fsize *2)/100);
    //printf("pix = %d, value = %d\n",((p->width- fsize *2)/100),value);
    LCD_DrawFillRectangle(window,p->x +fsize,p->y +fsize,p->x + p->w -fsize,p->y + p->h -fsize,0xffff);//100%
    if(value)
    LCD_DrawFillRectangle(window,p->x +fsize*1.5,p->y +fsize*1.5,p->x + (fsize * 0.5) +value,p->y + p->h -fsize*1.5,(GREEN));
    
    LCD_DrawFillRectangle(window,p->x +(p->w *1) +fsize,p->y +fsize,p->x + p->w +fsize*2,p->y + p->h - fsize,p->bc);
   
#endif
}

void window_create(struct window_t *window,int16_t x,int16_t y,uint16_t w,uint16_t h)
{
    window->table_index = 0;
    
    window->x = x;
    window->y = y;
    window->w = w;
    window->h = h;
    
    cw = window;
    
    for(int i=0;i<8;i++)
        window->list[i] = NULL;
    
}
void window_add(struct window_t *window, struct genery_param_t *param)
{
    window->list[window->table_index++] = param;
    cw = window;
}

void window_delete(struct window_t *window)
{
    return ;
}
void widget_do(struct window_t *window,struct genery_param_t *param)
{

    //default_config_check();
    switch(param->type){
        case WIDGET_TYPE_BUTTON:
            button_init(window,param);
            break;
        case WIDGET_TYPE_SW:
            sw_init(window,param);
            break;
        case WIDGET_TYPE_BAR:
            bar_init(window,param);
            break;
        case WIDGET_TYPE_BAT:
            battery_init(window,param);
            break;
        case WIDGET_TYPE_TEXTBOX:
            textbox_init(window,param);
            break;
        case WIDGET_TYPE_ICON:
            icon_init(window,param);
            break;
        case WIDGET_TYPE_TIMER:
            timer_init(window,param);
            break;
        case WIDGET_TYPE_METER:
            meter_init(window,param);
            break;
        case WIDGET_TYPE_MOUSE:
            mouse_init(window,param);
            break;
        default: break;
    }
}

extern void fb_update(void);
extern void fb_clear(uint16_t);
void window_show(struct window_t *window) 
{
    if(window == NULL)return;
    
    cw = window;
    fb_clear(0x0000);//清屏或者画背景图
    
	//轮询控件并绘制
    for(int i=0;i<8;i++){
        if(window->list[i] == NULL)break;
        struct genery_param_t *param = cw->list[i];

        int16_t a = ( param->x < window->w ) || ( (param->x +param->w) <window->w );
        int16_t b = ( param->x > 0 ) || ( (param->x +param->w) >0 );
        int16_t c = ( param->y < window->h ) || ( (param->y +param->h) <window->h );
        int16_t d = ( param->y > 0 ) || ( (param->y +param->h) >0 );
        
        if(a && b && c && d){ 
					widget_do(window,window->list[i]);
		}
        
    }
		
	fb_update();
}



void ts_event_input(uint8_t ev,int16_t x,int16_t y)
{
	/* 跳转顺序 [窗口事件] -> [控件事件] -> [控件回调] */
	
	
    //窗口事件跳转
    void (*cb)(struct window_t *,uint8_t,int16_t,int16_t) = cw->cb;
    if(cw->cb) cb(cw,ev,x,y);    
    
	//轮询窗口内控件
    for(int i=0;i<8;i++){
        if(cw->list[i] == NULL) continue;
        struct genery_param_t *param = cw->list[i];
        if(param->cb_widget == NULL)break;
        
        int16_t ox = cw->x;
        int16_t oy = cw->y;
        //坐标位于控件内
        //坐标位于控件周边10pixel
        if( (x > param->x + ox +( -10)) && (x < param->x + param->w + ox +( +10)) && \
            (y > param->y + oy +( -10)) && (y < param->y + param->h + oy +( +10))){
            void (*cb)(struct genery_param_t *,uint8_t,int16_t,int16_t) = param->cb_widget;
            cb(param,ev,x,y);
        }
    }
    window_show(cw);

}



